Package bg.smoc.model.manager

Source Code of bg.smoc.model.manager.GraderManager

/**
*
*/
package bg.smoc.model.manager;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TreeSet;

import kr.or.ioi2002.RMIServer.Job;
import kr.or.ioi2002.RMIServer.LogGrade;
import kr.or.ioi2002.RMIServer.LogSubmit;
import kr.or.ioi2002.RMIServer.LogTest;
import kr.or.ioi2002.RMIServer.RecordManager;
import kr.or.ioi2002.RMIServer.Syslog;
import kr.or.ioi2002.RMIServer.TempFile;
import kr.or.ioi2002.RMIServer.Util;
import kr.or.ioi2002.RMIServer.Job.JobType;
import kr.or.ioi2002.RMIServer.agent.LogGraderAgent;
import kr.or.ioi2002.RMIServer.agent.TCPListner;
import bg.smoc.agent.GraderAgent;
import bg.smoc.model.Contest;
import bg.smoc.model.Task;
import bg.smoc.model.TestGroup;

/**
* @author tsvetan.bogdanov@gmail.com
*
*/
public class GraderManager extends TCPListner {

    private static final int MAX_JOB_RETRY = 1;

    public static final String DIR_GRADE = "GRADE";

    protected MachineQueueManager machineQueueManager;

    protected HashMap<GraderAgent, String[]> obj2astr = new HashMap<GraderAgent, String[]>(); // [0]description

    private RecordManager recordManager = null;

    private File fileRoot = null;

    private GradingQueue gradingQueueManager;

    private ManagerMediator mediator;

    public GraderManager(int gradingPort, String workingDirectory) {
        super(gradingPort);
        recordManager = new RecordManager();
        gradingQueueManager = new GradingQueue(workingDirectory);
        machineQueueManager = new MachineQueueManager();
        this.fileRoot = new File(workingDirectory, "USERS");
    }

    public boolean[] hasSubmission(Contest contest, String login, Task task) {
        boolean[] res = new boolean[task.getNumberOfTests()];
        if (task == null || task.getType() == null || task.getType() != Task.PROBLEM_TYPE_OUTPUT) {
            File srcfile = null;
            if (task != null)
                srcfile = mediator.getSourceCode(contest, login, task.getName());

            for (int i = 0; i < task.getNumberOfTests(); ++i)
                res[i] = (srcfile != null);
        } else {
            for (int i = 0; i < task.getNumberOfTests(); ++i) {
                File srcfile = mediator.getSourceCode(contest, login, task.getNameAppenedTest(i));
                res[i] = (srcfile != null);
            }
        }
        return res;
    }

    public List<String> getResult(String contestId, String login, Task task) {
        List<String> result = new ArrayList<String>();

        if (task.getType() == null || task.getType() != Task.PROBLEM_TYPE_OUTPUT) {
            String raw_data = getResultFile(contestId, login, task.getName());
            StringTokenizer tokenizer = new StringTokenizer(raw_data, ",");
            tokenizer.nextToken(); // skip task name
            if (!tokenizer.hasMoreTokens()) {
                for (int i = 0; i < task.getNumberOfTests(); ++i) {
                    result.add("!");
                    return result;
                }
            }

            tokenizer.nextToken(); // skip language
            tokenizer.nextToken();
            tokenizer.nextToken();
            while (tokenizer.hasMoreTokens()) {
                tokenizer.nextToken(); // skip test number
                tokenizer.nextToken();
                result.add(tokenizer.nextToken());
                tokenizer.nextToken();
                tokenizer.nextToken();
                tokenizer.nextToken();
            }
        } else {
            for (int i = 0; i < task.getNumberOfTests(); ++i) {
                String raw_data = getResultFile(contestId, login, task.getNameAppenedTest(i)
                        .toLowerCase());
                StringTokenizer tokenizer = new StringTokenizer(raw_data, ",");
                tokenizer.nextToken(); // skip task name
                if (tokenizer.hasMoreTokens()) {
                    tokenizer.nextToken(); // skip language
                    tokenizer.nextToken();
                    tokenizer.nextToken();
                    tokenizer.nextToken(); // skip test number
                    tokenizer.nextToken();
                    result.add(tokenizer.nextToken());
                } else {
                    result.add("!");
                }
            }
        }
        return result;
    }

    private String getResultFile(String contestId, String userid, String task) {
        if (userid == null || task == null) {
            return "Not Graded(invalid userid or task";
        }

        File taskpath = getTaskPath(contestId, userid, task);
        File grade_output = new File(taskpath, task + ".grader.csv");
        if (!grade_output.exists()) {
            return "Not Graded";
        } else {
            try {
                BufferedReader in = new BufferedReader(new FileReader(grade_output));
                String output = in.readLine();
                in.close();
                return output;
            } catch (IOException e) {
                return "Not Graded(Problem found)";
            }
        }
    }

    private String getCompilerOutput(String contestId, String userid, String task) {
        if (userid == null || task == null) {
            return "System error! No ouput from compilation.";
        }

        File taskpath = getTaskPath(contestId, userid, task);
        File grade_output = new File(taskpath, task + ".compiler.out");
        if (!grade_output.exists()) {
            return "System error! No ouput from compilation.";
        } else {
            try {
                BufferedReader in = new BufferedReader(new FileReader(grade_output));
                StringBuffer result = new StringBuffer();
                String line = null;
                while ((line = in.readLine()) != null) {
                    result.append(line);
                    result.append("\n");
                }
                in.close();
                return result.toString();
            } catch (IOException e) {
                return "Not Graded(Problem found)";
            }
        }
    }

    private String getFullGraderCsv(String contestId, String userid, String task) {
        if (userid == null || task == null) {
            return "System error! No ouput from compilation.";
        }

        File taskpath = getTaskPath(contestId, userid, task);
        File grade_output = new File(taskpath, task + ".grader.csv");
        if (!grade_output.exists()) {
            return "System error! No ouput from compilation.";
        } else {
            try {
                BufferedReader in = new BufferedReader(new FileReader(grade_output));
                StringBuffer result = new StringBuffer();
                String line = null;
                while ((line = in.readLine()) != null) {
                    result.append(line);
                    result.append("\n");
                }
                in.close();
                return result.toString();
            } catch (IOException e) {
                return "Not Graded(Problem found)";
            }
        }
    }

    public boolean grade(Contest contest, String userId, String task) {
        File srcfile = mediator.getSourceCode(contest, userId, task);
        if (srcfile == null)
            return false;

        grade(contest.getId(),
                userId,
                task,
                mediator.getSourceCodeLanguage(contest, userId, task),
                srcfile);
        LogGrade.log(userId + ",START");
        return true;
    }

    public void grade(String contestId, String userid, String task, String language, File tmp) {
        Job job = new Job();
        job.setContestId(contestId);
        job.setUserid(userid);
        job.setType(JobType.GRADE);
        job.setTask(task);
        job.setLanguage(language);
        job.src = tmp;
        gradingQueueManager.push(job, null);
        dispatchJob();
    }

    public void submit(String contestId, String userId, Task task, String language, File tmp,
            String sourceFileName, JobRemovalNotified notified) {
        Job job = new Job();
        job.setContestId(contestId);
        job.setUserid(userId);
        if (task.isFeedbackEnabled()) {
            job.setType(JobType.FEEDBACK);
        } else {
            job.setType(JobType.SUBMIT);
        }
        // TODO: remove HACK
        if (task.getType() != Task.PROBLEM_TYPE_OUTPUT) {
            job.setTask(task.getName());
        } else {
            job.setTask(task.getName() + language);
        }
        job.setLanguage(language);
        job.srcFilename = sourceFileName;
        job.src = tmp;
        gradingQueueManager.push(job, notified);
        dispatchJob();
    }

    public void test(String contestId, String userId, String task, String language, TempFile tmp,
            TempFile tmp2, JobRemovalNotified notified) {
        Job job = new Job();
        job.setContestId(contestId);
        job.setUserid(userId);
        job.setType(JobType.TEST);
        job.setTask(task);
        job.setLanguage(language);
        job.src = tmp;
        job.stdin = tmp2;
        gradingQueueManager.push(job, notified);
        dispatchJob();
    }

    private void releaseMachine(Object objMachineid) {
        GraderAgent gm = null;
        if (objMachineid instanceof GraderAgent)
            gm = (GraderAgent) objMachineid;
        else {
            Syslog.log("!AgentManager: releaseMachine: obj not instanceof Agent");
            return;
        }

        boolean bBusy = machineQueueManager.releaseMachineFromBusyMode(gm);
        if (!bBusy)
            LogGraderAgent.log("!releaseMachine(set it idle): gm already not busy");
        dispatchJob();
    }

    private void dispatchJob() {
        dispatchJobToGrader(JobType.SETUP);
        dispatchJobToGrader(JobType.SUBMIT);
        dispatchJobToGrader(JobType.FEEDBACK);
        dispatchJobToGrader(JobType.TEST);
        dispatchJobToGrader(JobType.GRADE);
    }

    public void OnMsgGaEntry(Object objMachineid) {
        registerMachine(objMachineid);
    }

    private void registerMachine(Object objMachineid) {
        GraderAgent gm = null;
        if (objMachineid instanceof GraderAgent)
            gm = (GraderAgent) objMachineid;
        else {
            Syslog.log("!AgentManager: registerMachine: obj not instanceof Agent");
            return;
        }

        machineQueueManager.registerMachine(gm);

        // provide obj2astr
        String version = gm.getVersion();
        if (version == null)
            version = "";
        String desc = gm.getIP().toString();
        Date current = new Date();

        String[] aRecord = new String[5];
        aRecord[0] = desc;
        aRecord[1] = version;
        aRecord[2] = "RESERVED";
        aRecord[3] = kr.or.ioi2002.RMIServer.Util.sdfDate.format(current);
        aRecord[4] = kr.or.ioi2002.RMIServer.Util.sdfTime.format(current);
        Object objRet = obj2astr.put(gm, aRecord);
        if (objRet != null)
            Syslog.log("!AgentManager: registerMachine: overwriting existing key in obj2astr: "
                    + objRet.toString());

        LogGraderAgent.log("registerMachine[" + version + "][" + gm.getIP() + "]");

        dispatchJob();
    }

    public void OnMsgGaFail(Object objMachineid, Job job) {
        removeMachine(objMachineid);

        if (job != null) {
            job.iRetryCount++;
            boolean bRetrySuccess = false;
            if (job.iRetryCount <= MAX_JOB_RETRY) {
                bRetrySuccess = retryJob(job);
            }

            if (!bRetrySuccess) {
                String task = job.getTask();
                if (task == null)
                    task = "NA_OnGaFail";
                if (job.getType().equals(JobType.GRADE)) {
                    String userid = job.getUserid();
                    String gmid = job.gmid;
                    if (userid == null)
                        userid = "NA_FAILED";
                    if (gmid == null)
                        gmid = "NA_FAILED";
                    recordManager.add(job.getUserid()
                            + ","
                            + job.gmid
                            + ","
                            + task
                            + ",NA_FAILED,NA_FAILED,0,");
                } else {
                    if (job.getType() == JobType.SUBMIT || job.getType() == JobType.FEEDBACK) {
                        mediator.submitAttemptFailed(job.getContestId(), job.getUserid(), job
                                .getTask(), job.output);

                    }
                    // type error
                    Syslog.log("!IOIServer: OnGaFail: Job Type invalid");
                }
            }
        }
    }

    private boolean retryJob(Job job) {
        if (job == null
                || job.getUserid() == null
                || job.getTask() == null
                || job.src == null
                || job.getType() == null) {
            LogGraderAgent.log("!retryJob: tried to retry invalid job");
            return false;
        } else {
            job.output = null;
            gradingQueueManager.rePush(job);
            dispatchJob();
            LogGraderAgent.log("retryJob: " + job.getUserid() + "," + job.getType());
            return true;
        }
    }

    private void removeMachine(Object objMachineid) {
        GraderAgent gm = null;
        if (objMachineid instanceof GraderAgent)
            gm = (GraderAgent) objMachineid;
        else {
            Syslog.log("!AgentManager: removeMachine: obj not instanceof Agent");
            return;
        }

        String state = machineQueueManager.removeMachine(gm);

        String version = "";
        String date = "";
        String time = "";

        String[] astr = (String[]) obj2astr.remove(gm);
        if (astr == null) {
            Syslog.log("!AgentManager: removeMachine: obj not found in obj2astr: " + gm.toString());
        } else {
            if (astr[0] != null) {
            }
            if (astr[1] != null)
                version = astr[1];
            if (astr[3] != null)
                date = astr[3];
            if (astr[4] != null)
                time = astr[4];
        }

        LogGraderAgent.log("removeMachine["
                + version
                + "]["
                + gm.getIP()
                + "] registered at["
                + date
                + " "
                + time
                + "] in state ["
                + state
                + "] Job["
                + gm.getJob()
                + "]");
    }

    public void OnMsgTestDone(Object objMachineid, Job job) {
        releaseMachine(objMachineid);

        if (job != null && job.getType() != null && !job.getType().equals(JobType.TEST)) {
            Syslog.log("OnMsgGmTestDone: !job.type.equals(TEST)");
            return;
        }

        String task = job.getTask();
        if (task == null)
            task = "NA_GmTestDone";
        mediator.testFinish(job.getContestId(), job.getUserid(), task, job.output);
        if (job != null && job.result != null && job.result.equals("OK")) {
            LogTest.log(job.getUserid() + ",OK");
        } else {
            LogTest.log(job.getUserid() + ",FAIL");
        }
    }

    public void OnMsgGradeDone(Object objMachineid, Job job) {
        releaseMachine(objMachineid);

        if (job != null && job.getType() != null && !job.getType().equals(JobType.GRADE)) {
            Syslog.log("OnMsgGmGradeDone: !job.type.equals(GRADE)");
            return;
        }

        String strCsvRecord = job.getUserid() + "," + job.gmid + "," + new String(job.output);

        // append grader log
        if (job.log != null) {
            strCsvRecord = strCsvRecord + "," + (new String(job.log)).replace('\n', '|');
        }

        recordManager.add(strCsvRecord);

        if (job != null && job.result != null && job.result.equals("OK")) {
            LogGrade.log(job.getUserid() + ",OK");
        } else {
            LogGrade.log(job.getUserid() + ",FAIL");
        }
    }

    public void OnMsgSubmitDone(Object objMachineid, Job job) {
        // release GM
        releaseMachine(objMachineid);

        // process job
        if (job != null && job.getType() != null && !job.getType().equals(JobType.SUBMIT)) {
            // should not happen
            Syslog.log("OnMsgCaSubmitDone:"
                    + " job != null && "
                    + "job.type != null && "
                    + "!job.type.equals('SUBMIT')");
            return;
        }

        try {
            if (job != null && job.result != null && job.result.equals("OK")) {
                TempFile tmpsrc = null;
                if (job.src instanceof TempFile) {
                    tmpsrc = (TempFile) job.src;
                } else {
                    throw new java.io.IOException(
                            "!critical: OnMsgGmSubmitDone: job.src not type of TempFile-impossible");
                }
                String srcFilename = job.srcFilename;
                if (srcFilename == null) {
                    throw new java.io.IOException(
                            "!critical: OnMsgGmSubmitDone: job.srcFilename is null-impossible");
                }

                mediator.submitSourceCode(job.getContestId(),
                        job.getUserid(),
                        job.getTask(),
                        tmpsrc,
                        job.getLanguage(),
                        srcFilename,
                        job.output);
                if (job.getTask() == null)
                    job.setTask("");
                LogSubmit.log(job.getUserid() + ",OK," + job.getTask());
            } else {
                mediator.submitAttemptFailed(job.getContestId(),
                        job.getUserid(),
                        job.getTask(),
                        job.output);
                if (job.getTask() == null)
                    job.setTask("");
                LogSubmit.log(job.getUserid() + ",FAIL," + job.getTask());
            }
        } catch (java.io.IOException e) {
            Syslog.log("!OnMsgCaSubmitDone: " + Util.stackTrace(e));
        }
    }

    public void OnMsgFeedbackDone(Object objMachineid, Job job) {
        // release GM
        releaseMachine(objMachineid);

        // process job
        if (job != null && job.getType() != null && !job.getType().equals(JobType.FEEDBACK)) {
            // should not happen
            Syslog.log("OnMsgFeedbackDone:"
                    + " job != null && "
                    + "job.type != null && "
                    + "!job.type.equals(FEEDBACK)");
            return;
        }

        if (job != null) {
            if (job.result != null && job.result.equals("OK")) {
                swapFeedbackInformation(job);
            } else {
                swapFeedbackInformationWithGraderCsv(job);
            }
        }

        try {
            if (job != null && job.result != null && job.result.equals("OK")) {
                TempFile tmpsrc = null;
                if (job.src instanceof TempFile) {
                    tmpsrc = (TempFile) job.src;
                } else {
                    throw new java.io.IOException(
                            "!critical: OnMsgGmSubmitDone: job.src not type of TempFile-impossible");
                }
                String srcFilename = job.srcFilename;
                if (srcFilename == null) {
                    throw new java.io.IOException(
                            "!critical: OnMsgGmSubmitDone: job.srcFilename is null-impossible");
                }

                mediator.submitSourceCode(job.getContestId(),
                        job.getUserid(),
                        job.getTask(),
                        tmpsrc,
                        job.getLanguage(),
                        srcFilename,
                        job.output);
                if (job.getTask() == null)
                    job.setTask("");
                LogSubmit.log(job.getUserid() + ",OK," + job.getTask());
            } else {
                mediator.submitAttemptFailed(job.getContestId(),
                        job.getUserid(),
                        job.getTask(),
                        job.output);
                if (job.getTask() == null)
                    job.setTask("");
                LogSubmit.log(job.getUserid() + ",FAIL," + job.getTask());
            }
        } catch (IOException e) {
            Syslog.log("!OnMsgFeedbackDone: " + Util.stackTrace(e));
        }
    }

    private void swapFeedbackInformationWithGraderCsv(Job job) {
        Contest contest = mediator.getContestManager().getContest(job.getContestId());
        if (contest == null)
            return;
        Task task = contest.getTaskByName(job.getTask());
        if (task == null)
            return;

        StringBuffer output = new StringBuffer();
        output.append(getFullGraderCsv(contest.getId(), job.getUserid(), task.getName()));
        job.output = output.toString().getBytes();
    }

    /**
     * Swap job.out with feedback information.
     *
     * @param job
     */
    private void swapFeedbackInformation(Job job) {
        Contest contest = mediator.getContestManager().getContest(job.getContestId());
        if (contest == null)
            return;
        Task task = contest.getTaskByName(job.getTask());
        if (task == null)
            return;

        Set<Integer> testsCovered = new TreeSet<Integer>();
        for (TestGroup group : task.getTestGroups()) {
            if (group.isFeedbackEnabled()) {
                testsCovered.addAll(group.getTestCases());
            }
        }

        List<String> byTestResults = getResult(contest.getId(), job.getUserid(), task);
        int accepted = 0;
        int wrong = 0;
        int timeLimit = 0;
        int exception = 0;
        int system = 0;
        int compile = 0;
        for (int i = 0; i < task.getNumberOfTests(); ++i) {
            if (!testsCovered.contains(i + 1)) {
                continue;
            }

            String execResult = byTestResults.get(i);
            try {
                new BigDecimal(execResult);
                accepted++;
            } catch (NumberFormatException e) {
                if ("x".equals(execResult)) {
                    wrong++;
                } else if ("e".equals(execResult)) {
                    exception++;
                } else if ("t".equals(execResult)) {
                    timeLimit++;
                } else if ("c".equals(execResult)) {
                    compile++;
                } else {
                    System.out.print("Unknown output result:" + execResult);
                    system++;
                }
            }
        }

        StringBuffer output = new StringBuffer();
        output.append(getCompilerOutput(contest.getId(), job.getUserid(), task.getName()));
        if (testsCovered.size() == task.getNumberOfTests()) {
            output.append("Feedback for all test cases:\n");
        } else {
            output.append("Feedback for part of all test cases:\n");
        }
        asPercentage("Correct", output, accepted, testsCovered);
        asPercentage("Wrong answer", output, wrong, testsCovered);
        asPercentage("Time limit exceeded", output, timeLimit, testsCovered);
        asPercentage("Runtime exception", output, exception, testsCovered);
        asPercentage("Unknown type of error(s):", output, system, testsCovered);
        asPercentage("Compilation error", output, compile, testsCovered);
        job.output = output.toString().getBytes();
    }

    private void asPercentage(String type, StringBuffer output, int count, Set<Integer> testsCovered) {
        if (count > 0) {
            output.append(type);
            output.append(" : ");
            output.append(Integer.toString(100 * count / testsCovered.size()));
            output.append("%\n");
        }
    }

    public String[] getIdleMachineQueue() {
        return pretifyMachineQueue(machineQueueManager.getIdleMachineQueue());
    }

    public String[] getBusyMachineQueue() {
        return pretifyMachineQueue(machineQueueManager.getBusyMachineQueue());
    }

    private String[] pretifyMachineQueue(List<GraderAgent> machineQueue) {
        String[] printedQueue = new String[machineQueue.size()];
        int i = 0;
        for (GraderAgent agent : machineQueue) {
            StringBuffer sb = new StringBuffer();
            if (obj2astr.get(agent) != null)
                for (String machineInfo : obj2astr.get(agent)) {
                    sb.append(machineInfo);
                    sb.append(',');
                }
            printedQueue[i++] = sb.toString();
        }
        return printedQueue;
    }

    protected void dispatchJobToGrader(JobType jobType) {
        if (!gradingQueueManager.hasJob(jobType)) {
            return;
        }
        GraderAgent gm = machineQueueManager.moveMachineToBusy();
        if (gm == null) {
            return;
        }
        Job job = gradingQueueManager.popJob(jobType);

        if (gm != null && job != null && gm.assignJob(job)) {
            gradingQueueManager.markSuccessfullyAssignedJob(job);
        } else {
            machineQueueManager.releaseMachineFromBusyMode(gm);
            if (job != null)
                gradingQueueManager.rePush(job);
            dispatchJob();
        }
    }

    @Override
    protected void makeNewProduct(Socket socket) {
        new GraderAgent(this, mediator.getContestManager(), socket);
    }

    private List<String> printQueue(List<Job> queue) {
        List<String> itemList = new ArrayList<String>();

        for (Job job : queue)
            itemList.add(job.getUserid() + "|" + job.getTask());

        return itemList;
    }

    public File getTaskPath(String contestId, String userid, String task) {
        return new File(new File(new File(new File(fileRoot, contestId), userid), DIR_GRADE), task);
    }

    public List<String> getSubmitQueue() {
        return printQueue(gradingQueueManager.getQueue(JobType.SUBMIT));
    }

    public List<String> getFeedbackQueue() {
        return printQueue(gradingQueueManager.getQueue(JobType.FEEDBACK));
    }

    public List<String> getTestQueue() {
        return printQueue(gradingQueueManager.getQueue(JobType.TEST));
    }

    public List<String> getGradeQueue() {
        return printQueue(gradingQueueManager.getQueue(JobType.GRADE));
    }

    public void setMediator(ManagerMediator managerMediator) {
        mediator = managerMediator;
    }

    public void pushTestData(Contest contest) {
        int jobsCount = machineQueueManager.markAllGradersToUpdate(contest);
        for (int i = 0; i < jobsCount; ++i) {
            Job job = new Job();
            job.setContestId(contest.getId());
            job.setType(JobType.SETUP);
            gradingQueueManager.push(job, null);
            dispatchJob();
        }
    }
}
TOP

Related Classes of bg.smoc.model.manager.GraderManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.